package net.stogi.dsper.ui.client.module.user;

import java.util.ArrayList;
import java.util.List;

import net.stogi.common.gwt.dispatch.client.core.ActionManager;
import net.stogi.common.gwt.frame.client.core.EventBus;
import net.stogi.common.gwt.frame.client.mvp.AbstractPresenter;
import net.stogi.common.mvp.core.behavior.Behavior;
import net.stogi.common.mvp.core.model.KeyValues;
import net.stogi.dsper.api.dto.DataSourceDto;
import net.stogi.dsper.api.dto.TagDto;
import net.stogi.dsper.api.dto.UserProfileDto;
import net.stogi.dsper.ui.client.module.datasource.DataSourceSelectorClosedEvent;
import net.stogi.dsper.ui.client.module.datasource.DataSourceSelectorClosedHandler;
import net.stogi.dsper.ui.client.module.datasource.DataSourcesSelectedEvent;
import net.stogi.dsper.ui.client.module.datasource.DataSourcesSelectedHandler;
import net.stogi.dsper.ui.client.module.datasource.OpenDataSourceSelectorEvent;
import net.stogi.dsper.ui.client.module.tag.OpenTagSelectorEvent;
import net.stogi.dsper.ui.client.module.tag.TagSelectorClosedEvent;
import net.stogi.dsper.ui.client.module.tag.TagSelectorClosedHandler;
import net.stogi.dsper.ui.client.module.tag.TagsSelectedEvent;
import net.stogi.dsper.ui.client.module.tag.TagsSelectedHandler;
import net.stogi.dsper.ui.shared.module.user.SaveUserProfileAction;
import net.stogi.dsper.ui.shared.module.user.SaveUserProfileResult;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

class UserProfileEditorPresenter extends AbstractPresenter {

	private UserProfileEditorView userProfileEditorView;

	private UserProfileDto userProfileModel;

	public UserProfileEditorPresenter(UserProfileEditorView userProfileEditorView, ActionManager actionManager, EventBus eventBus) {
		super(actionManager, eventBus);
		this.userProfileEditorView = userProfileEditorView;
		initBehavior();
		initHandlers();
	}

	@Override
	protected void initBehavior() {
		userProfileEditorView.setAddDataSourcesBehavior(new Behavior() {

			@Override
			public void behave() {
				userProfileEditorView.block();
				eventBus.fireEvent(new OpenDataSourceSelectorEvent());
			}
		});
		userProfileEditorView.setAddTagsBehavior(new Behavior() {

			@Override
			public void behave() {
				userProfileEditorView.block();
				eventBus.fireEvent(new OpenTagSelectorEvent());
			}
		});
		userProfileEditorView.setCancelBehavior(new Behavior() {

			@Override
			public void behave() {
				userProfileEditorView.disappear();
				eventBus.fireEvent(new UserProfileEditorClosedEvent(false));
			}
		});
		userProfileEditorView.setSaveBehavior(new Behavior() {

			@Override
			public void behave() {
				internalCollectUserProfile(userProfileModel);
				userProfileEditorView.block();
				executeSaveUserProfile(userProfileModel);
			}
		});
	}

	@Override
	protected void initHandlers() {
		eventBus.addHandler(DataSourceSelectorClosedEvent.TYPE, new DataSourceSelectorClosedHandler() {

			@Override
			public void onDataSourceSelectorClosed(DataSourceSelectorClosedEvent event) {
				userProfileEditorView.unblock();
			}
		});
		eventBus.addHandler(DataSourcesSelectedEvent.TYPE, new DataSourcesSelectedHandler() {

			@Override
			public void onDataSourcesSelected(DataSourcesSelectedEvent event) {
				userProfileModel.setDataSources(event.getSelectedDataSources());
				internalDisplayDataSources(userProfileModel.getDataSources());
				userProfileEditorView.unblock();
			}
		});
		eventBus.addHandler(TagSelectorClosedEvent.TYPE, new TagSelectorClosedHandler() {

			@Override
			public void onTagSelectorClosed(TagSelectorClosedEvent event) {
				userProfileEditorView.unblock();
			}
		});
		eventBus.addHandler(TagsSelectedEvent.TYPE, new TagsSelectedHandler() {

			@Override
			public void onTagsSelected(TagsSelectedEvent event) {
				userProfileModel.setTags(event.getSelectedTags());
				internalDisplayTags(userProfileModel.getTags());
				userProfileEditorView.unblock();
			}
		});
		eventBus.addHandler(OpenUserProfileEditorEvent.TYPE, new OpenUserProfileEditorHandler() {

			@Override
			public void onOpenUserProfileEditor(OpenUserProfileEditorEvent event) {
				userProfileModel = event.getUserProfile();
				internalDisplayUserProfile(userProfileModel);
				userProfileEditorView.unblock();
				userProfileEditorView.appear();
			}
		});
	}

	private void executeSaveUserProfile(UserProfileDto userProfile) {
		actionManager.execute(new SaveUserProfileAction(userProfile), new AsyncCallback<SaveUserProfileResult>() {

			@Override
			public void onFailure(Throwable caught) {
				userProfileEditorView.unblock();
				internalHandleException(caught);
			}

			@Override
			public void onSuccess(SaveUserProfileResult result) {
				userProfileEditorView.unblock();
				userProfileEditorView.disappear();
				eventBus.fireEvent(new UserProfileEditorClosedEvent(true));
			}
		});
	}

	private void internalCollectUserProfile(UserProfileDto userProfile) {
		userProfile.setName(userProfileEditorView.collectName());
	}

	private void internalDisplayDataSources(List<DataSourceDto> dataSourceList) {
		List<KeyValues<Long>> modelList = new ArrayList<KeyValues<Long>>();
		for (DataSourceDto dataSource : dataSourceList) {
			KeyValues<Long> model = new KeyValues<Long>(dataSource.getId());
			model.setValue("name", dataSource.getName());
			modelList.add(model);
		}
		userProfileEditorView.displayDataSources(modelList);
	}

	private void internalDisplayTags(List<TagDto> tagList) {
		List<KeyValues<Long>> modelList = new ArrayList<KeyValues<Long>>();
		for (TagDto tag : tagList) {
			KeyValues<Long> model = new KeyValues<Long>(tag.getId());
			model.setValue("value", tag.getValue());
			modelList.add(model);
		}
		userProfileEditorView.displayTags(modelList);
	}

	private void internalDisplayUserProfile(UserProfileDto userProfile) {
		userProfileEditorView.displayName(userProfile.getName());
		internalDisplayDataSources(userProfile.getDataSources());
		internalDisplayTags(userProfile.getTags());
	}

	private void internalHandleException(Throwable caught) {
		// TODO: Add some nice message module in order to show messages from
		// exceptions to user.
		GWT.log("execute*: fail", null);
	}
}
